use crate::json_basic::JsonNode;
use crate::json_token::JsonToken;
use std::collections::{HashMap, LinkedList};

/// 语法分析

struct JsonParser {
    token: LinkedList<JsonToken>,
}

impl JsonParser {
    pub fn new(token: LinkedList<JsonToken>) -> Self {
        Self { token: token }
    }

    pub fn parse(&mut self) -> Option<JsonNode> {
        self.parse_value()
    }
    pub fn parse_value(&mut self) -> Option<JsonNode> {
        match self.token.pop_front() {
            Some(JsonToken::String(s)) => Some(JsonNode::String(s)),
            Some(JsonToken::Number(n)) => Some(JsonNode::Number(n)),
            Some(JsonToken::Boolean(b)) => Some(JsonNode::Boolean(b)),
            Some(JsonToken::Null) => Some(JsonNode::Null),
            Some(JsonToken::LeftBrace) => self.parse_object(),
            Some(JsonToken::LeftBracket) => self.parse_array(),
            _ => None,
        }
    }

    /// 拼装 object 对象
    /// 先搞一个存放对象的 map
    /// 循环从 链表 中 pop 数据
    /// 如果是  }(右大括号) 就把放数据的 map 返回
    /// 如果不是 }(右大括号) 那就是有数据, 碰到 :(冒号) 要递归遍历 value
    /// 把  key 和 递归遍历好的 value 一起放进 map
    /// 如果 接下来是 ,(逗号) 就继续, 如果接下来是  }(右大括号) 就把放数据的 map 返回
    /// 其余情况返回空
    fn parse_object(&mut self) -> Option<JsonNode> {
        let mut obj = HashMap::new();
        loop {
            match self.token.pop_front() {
                Some(JsonToken::RightBrace) => break Some(JsonNode::Object(obj)), // }(右大括号)
                Some(JsonToken::String(key)) => match self.token.pop_front() {
                    // 数据
                    Some(JsonToken::Colon) => {
                        // : 冒号
                        let value = self.parse_value()?;
                        obj.insert(key, value);
                        match self.token.pop_front() {
                            Some(JsonToken::Comma) => continue, // 是 ,(逗号) 就继续
                            Some(JsonToken::RightBrace) => break Some(JsonNode::Object(obj)),
                            _ => break None,
                        }
                    }
                    _ => break None,
                },
                _ => break None,
            }
        }
    }

    fn parse_array(&mut self) -> Option<JsonNode> {
        let mut arr = Vec::new();
        loop {
            match self.token.front() {
                Some(JsonToken::RightBracket) => {
                    // }(右大括号)
                    self.token.pop_front();
                    break Some(JsonNode::Array(arr));
                }
                Some(JsonToken::Comma) => {
                    // :(冒号)
                    self.token.pop_front();
                    continue;
                }
                Some(_) => {
                    // 数据 递归
                    arr.push(self.parse_value()?);
                }
                _ => break None,
            }
        }
    }
}

pub fn parse_all(tokens: LinkedList<JsonToken>) -> Option<JsonNode> {
    let mut parser = JsonParser::new(tokens);
    parser.parse()
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::json_lexer;
    #[test]
    fn test_parse_all() {
        let json_str = "{\"first name\":\"Yiran\", \"last name\": \"王\", \"age\":20,\"is_student\":true,\"courses\":[{\"name\":\"CPEN 212\",\"credits\":4},{\"name\":\"CPSC 221\",\"credits\":4},{\"name\":\"Math 256\",\"credits\":3}],\"address\":{\"street\":\"1935 Lower Mall\",\"city\":\"Vancouver\",\"postal_code\":\"V6T 1X1\"},\"friends\":[{\"name\":\"Tommy\",\"age\":20},{\"name\":\"Joe\",\"age\":20}],\"graduated\":false, \"university\": \"UBC\"}";
        let list = json_lexer::parse_all(json_str).unwrap();
        println!("list: {:?}", list);
        let json = parse_all(list);
        println!("json: {:?}", json);
    }
}
